//
// $Id$

package com.samskievert.cactusboom;

import com.threerings.media.VirtualMediaPanel;
import com.threerings.toybox.util.ToyBoxContext;

import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceObject;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Font;
import java.awt.Point;

 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import com.threerings.presents.dobj.DSet;
 
 import com.threerings.presents.dobj.EntryAddedEvent;
 import com.threerings.presents.dobj.EntryUpdatedEvent;
 import com.threerings.presents.dobj.EntryRemovedEvent;
 import com.threerings.presents.dobj.SetListener;
 
 import com.threerings.util.Name;

 import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionAdapter;
 import java.awt.event.MouseAdapter;
 
 import java.awt.Font;
 import com.samskivert.swing.Label;
 import com.threerings.media.animation.FloatingTextAnimation;
 import com.threerings.parlor.media.ScoreAnimation;
 import com.threerings.media.sprite.Sprite;
import javax.swing.plaf.SliderUI;
import java.awt.geom.AffineTransform;


import com.threerings.media.image.BufferedMirage;
import com.threerings.media.image.Mirage;

/**
 * Displays the main game interface (the board).
 */

/**
 * I'll eventually want a new cursor...
 *    -one that starts as a pair of dice...
 *    -then shows available moves and # of moves remaining
 */
public class CBTerritoryView extends VirtualMediaPanel
    implements PlaceView, SetListener
{
    

    
    /**
     * Constructs a view which will initialize itself and prepare to display
     * the game board.
     */
    public CBTerritoryView (ToyBoxContext ctx, CBController ctrl)
    {
        super(ctx.getFrameManager());
        _ctx = ctx;
        _ctrl = ctrl;
        
        //create the logic class
        _logic = new CBLogic(8);
        
        _cursor.setRenderOrder(50);
        
       // listen for mouse motion and presses
       addMouseListener(new MouseAdapter() {
           public void mousePressed (MouseEvent e) {
               if(!_paused){
               if(_cursor.didRoll && _cursor.rollCount == 0){
                   CBObject.Cactus cactus = _cursor.getPiece();
                   _logic.setState(_gameobj);
                   if (_logic.isLegalMove(cactus,2)) {
                       if(_cursor.moveType == 3){
                        _movePath = _logic.getPath(cactus);
                        /*
                        Point nextLoc = (Point)_movePath.pathPoints.get(0);
                        if(_logic.getDirection(nextLoc) >= 0) {
                            _ctrl.moveCowboy(_logic.getDirection(nextLoc));
                            //now pop the top move off of the stack
                            _movePath = new CBLogic.movePath(_movePath,1,_movePath.pathPoints.size());
                        }*/
                       }
                       _logic.setState(_gameobj);
                       //_cursor.setPosition(cactus.x, cactus.y,_logic, _gameobj);
                    }
               }else if(_cursor.didRoll && _cursor.rollCount > 0){
                   System.out.println("Still rolling! Be patient.");
               }else{
                   _cursor.didRoll = true;
               }
           }
       }});

       
       // listen for mouse motion
       addMouseMotionListener(new MouseMotionAdapter() {
           public void mouseMoved (MouseEvent e) {
               if(!_paused){
               _logic.setState(_gameobj);
               //_logic.setTerritoryState(_gameobj);
               int tx = e.getX();
               int ty = e.getY();
               if(gameStarted && _cursor != null && _gameobj != null & _logic != null){ 
                   if(!_cursor.didRoll || (_cursor.didRoll && _cursor.rollCount == 0)) _cursor.setPosition(tx, ty,_logic, _gameobj);
               }
               
           }}
       });

       
    }
    
   //load the cowboy images from the media folder  
   //we only want to load the ones we're actually using...
   public void loadTVImages(){
       String[] filenames = {"media/cowboy_blue.png","media/cowboy_red.png","media/cowboy_green.png","media/cowboy_yellow.png"};
       for(int i = 0; i < _gameobj.getPlayers().length; i++){
           TVImages[i] = new BufferedMirage(_ctx.loadImage(filenames[i]));
       }
   }
   
   public BufferedMirage getTVImage(int whichImage){
       return TVImages[whichImage];
   }
   
   public void enableCursor()
   {
    gameStarted = true;
    //_cursor.fixCactus(_gameobj.NUMSPIKES);
   }
   
   /**
   * Floats the supplied text over the board.
   */
   public void displayFloatingText (String text)
   {
       Label label = ScoreAnimation.createLabel(
           text, Color.white, new Font("Helvetica", Font.BOLD, 48), this);
       int lx = (getWidth() - label.getSize().width)/2;
       int ly = (getHeight() - label.getSize().height)/2;
       addAnimation(new FloatingTextAnimation(label, lx, ly));
   }
   
   public void displayDiceText (String text)
   {
       Label label = ScoreAnimation.createLabel(
       text, Color.white, new Font("Helvetica", Font.BOLD, 32), this);
       int lx = _cursor.getX();
       int ly = _cursor.getY();
       addAnimation(new FloatingTextAnimation(label, lx + 12, ly));
   }

    /**
    * Activates "placing" mode which allows the user to place a piece of the
    * specified color.
    */
   public void setPlacingMode (int color)
   {
       // update our logic with the current board state
       _logic.setState(_gameobj);
       //_logic.setTerritoryState(_gameobj);
 
       if(getSpriteManager().isManaged(_cursor)) removeSprite(_cursor);
       
       if (color != -1) {
           _cursor.setColor(color);
           _cursor.setImage(TVImages[color]);
           addSprite(_cursor);
       } else if (isManaged(_cursor)) {
           removeSprite(_cursor);
       }
   }
 
    // from interface PlaceView
    public void willEnterPlace (PlaceObject plobj)
    {
        _gameobj = (CBObject)plobj;
        _gameobj.addListener(this);
        
        loadTVImages();  //load the Territory View Images
                
        //create a Cowboy for each player
        for(CBObject.Cowboy cowboy : _gameobj.cowboys){
            addCowboySprite(cowboy);
        } 
        
        //show all the pickups on the board
        for(CBObject.Pickup pickup : _gameobj.pickups){
            addPickupSprite(pickup);
        } 
        
        //temporary hackery
        setPlacingMode(CBObject.BLUE);
    }

    // from interface PlaceView
    public void didLeavePlace (PlaceObject plobj)
    {
         _gameobj.removeListener(this);
         _gameobj = null;
    }

         // from interface SetListener
     public void entryAdded (EntryAddedEvent event)
     {
         
         if (event.getName().equals(CBObject.COWBOYS)){
             //add a cowboy for the newly created piece
             addCowboySprite((CBObject.Cowboy)event.getEntry());
         }
         
         if (event.getName().equals(CBObject.PICKUPS)){
             //add a cowboy for the newly created piece
             addPickupSprite((CBObject.Pickup)event.getEntry());
         }
         
     }
 
     // from interface SetListener
     public void entryUpdated (EntryUpdatedEvent event)
     {
         
         if (event.getName().equals(CBObject.COWBOYS)) {
             //System.out.println("Cowboy updated!");
             // update the sprite that is displaying the updated piece
             CBObject.Cowboy cowboy = (CBObject.Cowboy)event.getEntry();
             //System.out.println("Told Cowboy " + cowboy.getKey() + " to mosey along!");
             //if(_cowboySprites.containsKey(cowboy.getKey())) System.out.println("And my spriteList recognized that value!");
             _cowboySprites.get(cowboy.getKey()).updateCowboy(cowboy);
         }
         
   
    }
     
     // from interface SetListener
     public void entryRemoved (EntryRemovedEvent event)
     {
          
          if (event.getName().equals(CBObject.PICKUPS)) {
             CBObject.Pickup pickup = (CBObject.Pickup)event.getOldEntry();
             removeSprite(_pickupSprites.get(pickup.getKey()));
          }
     }
 

     protected void addCowboySprite (CBObject.Cowboy cowboy)
     {
         if(_cowboySprites.containsKey(cowboy.getKey())){
            System.out.println("Caught trying to add a dupe!");
         }else{
         CowboySprite sprite = new CowboySprite(cowboy, _size, TVImages[cowboy.owner]);
         _cowboySprites.put(cowboy.getKey(), sprite);
         System.out.println("Cowboy " + cowboy.getKey() + " added.");
         addSprite(sprite);
         }
     }
     
     protected void addGameOverSprite ()
     {
         Name[] names = _gameobj.getPlayers();
         GameOverSprite sprite = new GameOverSprite(names[_gameobj.bigWinner].toString(), TVImages[_gameobj.bigWinner]);
         System.out.println("GameOverSprite added.");
         addSprite(sprite);
     }
          
     
      /**
      * Ditto for pickups.
      */
     protected void addPickupSprite (CBObject.Pickup pickup)
     {
         PickupSprite sprite = new PickupSprite(pickup, _gameobj);
         _pickupSprites.put(pickup.getKey(), sprite);
         addSprite(sprite);         
     }
     
 
   @Override // from JComponent
   public Dimension getPreferredSize ()
   {
       //System.out.println("Preferred Size called (" + (int)(_size.width * SCALE * CactusSprite.SIZE + 1) +  "," + (int)(_size.height * SCALE * CactusSprite.SIZE + 1) + ")");
       //return new Dimension(200,200);
       
       return new Dimension((int)(_size.width * CactusSprite.SIZE + 1),
                            (int)(_size.height * CactusSprite.SIZE + 1));
       
   }
   
   @Override //from MediaPanel
   public void tick(long tickStamp)
   {
       super.tick(tickStamp);
       
       //this code check to see if the active player's
       //sprite is still moving
       if(gameStarted && _gameobj!= null &&  _gameobj.movePoints != null){
           boolean allEmpty = true;
           int whoMoving = -1;
           Name[] plist = _gameobj.getPlayers();
           Name cp = _gameobj.getTurnHolder();
           for(int i = 0; i < _gameobj.movePoints.length; i++){
               if(plist[i].equals(cp)) whoMoving = i;
               if(_gameobj.movePoints[i] > 0){
                   allEmpty = false;
               }
           }

           if(_cowboySprites.containsKey(whoMoving)){
               //if that player is all out of moves, time to stake a claim!
               if( allEmpty && !_cowboySprites.get(whoMoving).isMoving()){
                    System.out.println("No more moves!"); 
                   _ctrl.toggleView();
                   //reset the cursor for the next turn
                   _cursor.didRoll = false;
                    _cursor.rollCount = 30;
               }else if(!_cowboySprites.get(whoMoving).isMoving()){
                //if someone still has moves left...
                //and there sprite isn't moving any more...
                //might as well send them along the rest of the path!
                if(_movePath != null && _movePath.pathPoints.size() > 0)
                {
                    Point nextLoc = (Point)_movePath.pathPoints.get(0);
                    int whichDir = _logic.getDirection(nextLoc);
                    int numMoves = 1;
                    
                    if(_logic.getDirection(nextLoc) >= 0) {
                            _ctrl.moveCowboy(_logic.getDirection(nextLoc));
                            //now pop the top move off of the stack
                            _movePath = new CBLogic.movePath(_movePath,1,_movePath.pathPoints.size());
                            //go ahead and pass along any other moves in the same direction
                            if(_movePath.pathPoints.size() > 0){
                                numMoves++;
                                nextLoc = (Point)_movePath.pathPoints.get(0);
                                while(_movePath.pathPoints.size() > 0 && _logic.getDirection(nextLoc) == whichDir){
                                    _ctrl.moveCowboy(_logic.getDirection(nextLoc));
                                    _movePath = new CBLogic.movePath(_movePath,1,_movePath.pathPoints.size());
                                    if(_movePath.pathPoints.size() > 0) nextLoc = (Point)_movePath.pathPoints.get(0);
                                }
                            }
                        }
                }
               }
           }else{
               //System.out.println("couldn't find cowboySprite with key " + whoMoving);
           }
       }
       
       //this is the little flashy result of the "dice roll"
       if(_cursor.rollCount == 1) displayDiceText(_gameobj.movePoints[_cursor.getPiece().owner] + "");
       
       
       
       
       
   }
   
   protected Rectangle expandBounds(Rectangle r, Point p)
   {
       System.out.println(p.toString());
       if(r.contains(p)) return r;
       if(p.x < r.x) {r.width += (r.x - p.x); r.x = p.x;}
       if(p.y < r.y) {r.height += (r.y - p.y); r.y = p.y;}
       if(p.x + CactusSprite.SIZE >= r.x + r.width) r.width += (p.x + CactusSprite.SIZE) - (r.x + r.width);
       if(p.y + CactusSprite.SIZE >= r.y + r.height) r.height += (p.y + CactusSprite.SIZE) - (r.y + r.height);
       System.out.println("Expanded: " + r.toString());
       return r;
   }
   
   @Override // from MediaPanel
   protected void paintBehind (Graphics2D gfx, Rectangle dirtyRect)
   {
       /*
       _logic.setState(_gameobj);
       int p = _cursor.getPiece().owner;
       ArrayList<Point> allMoves= new ArrayList<Point>();
       if(p != 0){
           if(_cowboySprites.containsKey(p)){
               CBObject.Cowboy cowboy = _cowboySprites.get(p).getCowboy();
               allMoves = _logic.getLegalMoves(new Point(cowboy.x,cowboy.y),_gameobj.movePoints[p]);
           }
       }
        
       
       if(_cursor.rollCount == 1 && _ctrl.turnCheck()){
           System.out.println(dirtyRect.toString());
           Rectangle realDirty = new Rectangle(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
           for(Point point : allMoves){
               realDirty = expandBounds(realDirty, new Point(point.x*CactusSprite.SIZE, point.y*CactusSprite.SIZE));
           }
           //actually need to expand it one more square in each direction to clean out the old ones
           realDirty.x -= CactusSprite.SIZE;
           realDirty.y -= CactusSprite.SIZE;
           realDirty.width += 2*CactusSprite.SIZE;
           realDirty.height += 2*CactusSprite.SIZE;
           if(realDirty.equals(dirtyRect)){
               System.out.println("No update needed!");
           }else{
                System.out.println("Update needed! " + dirtyRect.toString());
                dirtyScreenRect(realDirty);
           }
       }
       **/
       
       super.paintBehind(gfx, dirtyRect);
       Color[] COLORLIST = new Color[] {new Color(225,219,196), new Color(128,128,255), new Color(255,128,128), new Color(128,255,128),new Color(252,236,202)};
       
       // fill in our background color
       gfx.setColor(new Color(225,219,196));
       gfx.fill(dirtyRect);
       
       for(int i = 0; i < _size.width; i++){
           for(int j = 0; j < _size.height; j++){
               if(_gameobj.claims.containsKey(i*8 + j)){
                   CBObject.Claim claim = (CBObject.Claim)_gameobj.claims.get(i*8 + j);
                   gfx.setColor(COLORLIST[claim.owner + 1]);
                   int cx = i*CactusSprite.SIZE;  int cw = CactusSprite.SIZE;
                   int cy = j*CactusSprite.SIZE;  int ch = CactusSprite.SIZE;                   
                   gfx.fillRect(cx,cy,cw,ch);
                   gfx.setColor(Color.black);
                   gfx.drawRect(cx,cy,cw-1,ch-1);
                   gfx.setColor(new Color(128,128,128));
                   Font font =  new Font("arial",0,18);
                   gfx.setFont(font);
                   if(claim.strength < 1000) gfx.drawString("" + claim.strength,(int)(cx + cw/2 - 6),(int)(cy + ch/2 + 5));
               }else{
                   //if it's not claimed just draw a normal square
                   int cx = i*CactusSprite.SIZE;  int cw = CactusSprite.SIZE;
                   int cy = j*CactusSprite.SIZE;  int ch = CactusSprite.SIZE;                   
                   gfx.setColor(Color.black);
                   gfx.drawRect(cx,cy,cw-1,ch-1);
               }
               /*
               //if a move is in range and it's our turn, put a rect of the acting player's color around it 
               if(_ctrl.turnCheck() && _cursor.didRoll == true && _cursor.rollCount == 0){
                   CBObject.Cactus cactus = new CBObject.Cactus();
                   cactus.x = i; cactus.y = j;
                   //active player
                   //int p = _cursor.getPiece().owner;
                   Point t = new Point(i,j);
                   if(p >= 0){
                       if(allMoves.contains(t)){
                           Color[] CL = new Color[] {Color.blue, Color.red, Color.green, Color.orange};
                           gfx.setColor(CL[_cursor.getPiece().owner]);
                           int cx = i*CactusSprite.SIZE;  int cw = CactusSprite.SIZE;
                           int cy = j*CactusSprite.SIZE;  int ch = CactusSprite.SIZE;                   

                           gfx.fillRect(cx,cy,cw,3);
                           gfx.fillRect(cx,cy,3,ch);
                           gfx.fillRect(cx,cy+ch-4,cw,3);
                           gfx.fillRect(cx+cw-4,cy,3,ch);
                           gfx.setColor(Color.black);
                           gfx.drawRect(cx,cy,cw-1,ch-1);
                           gfx.drawRect(cx+3,cy+3,cw-6,ch-6);
                
                       }else{
                        //System.out.println(allMoves.size() + " in allMoves");   
                       }
                   }
               } */
           }
       }
       

       
   }
   
   /** In case a user clicked several squares away...this holds the movePath */
   protected CBLogic.movePath _movePath;
   
   /** Used to determine legal moves. */
   protected CBLogic _logic;

   /** Displays a cursor when we're allowing the user to place a piece. */
   protected CursorSpriteTerr _cursor = new CursorSpriteTerr();
   
  boolean gameStarted = false;
   
  /** Contains a mapping from piece id to the sprite for that piece. */
   protected HashMap<Comparable, CowboySprite> _cowboySprites = 
         new HashMap<Comparable,CowboySprite>();
   
  /** Contains a mapping from piece id to the sprite for that piece. */
   protected HashMap<Comparable, PickupSprite> _pickupSprites = 
         new HashMap<Comparable,PickupSprite>();   
 
   protected BufferedMirage[] TVImages = new BufferedMirage[4];
   /**
     * The _size of the board.
     */
   protected Dimension _size = new Dimension(8, 8);

   /** Provides access to client services. */
    protected ToyBoxContext _ctx;

    /** A reference to our game object. */
    protected CBObject _gameobj;
    
   /** The game controller to which we dispatch user actions. */
   protected CBController _ctrl;
    
}

